<?php

if (! defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package CodeIgniter
 * @author ExpressionEngine Dev Team
 * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
 * @license http://codeigniter.com/user_guide/license.html
 * @link http://codeigniter.com
 * @since Version 1.3.1
 * @filesource
 *
 */
    
// ------------------------------------------------------------------------

/**
 * HTML Table Generating Class
 *
 * Lets you create tables manually or from database result objects, or arrays.
 *
 * @package CodeIgniter
 * @subpackage Libraries
 * @category HTML Tables
 * @author ExpressionEngine Dev Team
 * @link http://codeigniter.com/user_guide/libraries/uri.html
 */
class CI_Table
{

    var $rows = array();

    var $heading = array();

    var $auto_heading = TRUE;

    var $caption = NULL;

    var $template = NULL;

    var $newline = "\n";

    var $empty_cells = "";

    var $function = FALSE;

    public function __construct ()
    {
        log_message('debug', "Table Class Initialized");
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Set the template
     *
     * @access public
     * @param
     *            array
     * @return void
     */
    function set_template ($template)
    {
        if (! is_array($template)) {
            return FALSE;
        }
        
        $this->template = $template;
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Set the table heading
     *
     * Can be passed as an array or discreet params
     *
     * @access public
     * @param
     *            mixed
     * @return void
     */
    function set_heading ()
    {
        $args = func_get_args();
        $this->heading = $this->_prep_args($args);
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Set columns.
     * Takes a one-dimensional array as input and creates
     * a multi-dimensional array with a depth equal to the number of
     * columns. This allows a single array with many elements to be
     * displayed in a table that has a fixed column count.
     *
     * @access public
     * @param
     *            array
     * @param
     *            int
     * @return void
     */
    function make_columns ($array = array(), $col_limit = 0)
    {
        if (! is_array($array) or count($array) == 0) {
            return FALSE;
        }
        
        // Turn off the auto-heading feature since it's doubtful we
        // will want headings from a one-dimensional array
        $this->auto_heading = FALSE;
        
        if ($col_limit == 0) {
            return $array;
        }
        
        $new = array();
        while (count($array) > 0) {
            $temp = array_splice($array, 0, $col_limit);
            
            if (count($temp) < $col_limit) {
                for ($i = count($temp); $i < $col_limit; $i ++) {
                    $temp[] = '&nbsp;';
                }
            }
            
            $new[] = $temp;
        }
        
        return $new;
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Set "empty" cells
     *
     * Can be passed as an array or discreet params
     *
     * @access public
     * @param
     *            mixed
     * @return void
     */
    function set_empty ($value)
    {
        $this->empty_cells = $value;
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Add a table row
     *
     * Can be passed as an array or discreet params
     *
     * @access public
     * @param
     *            mixed
     * @return void
     */
    function add_row ()
    {
        $args = func_get_args();
        $this->rows[] = $this->_prep_args($args);
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Prep Args
     *
     * Ensures a standard associative array format for all cell data
     *
     * @access public
     * @param
     *            type
     * @return type
     */
    function _prep_args ($args)
    {
        // If there is no $args[0], skip this and treat as an associative array
        // This can happen if there is only a single key, for example this is
        // passed to table->generate
        // array(array('foo'=>'bar'))
        if (isset($args[0]) and (count($args) == 1 && is_array($args[0]))) {
            // args sent as indexed array
            if (! isset($args[0]['data'])) {
                foreach ($args[0] as $key => $val) {
                    if (is_array($val) && isset($val['data'])) {
                        $args[$key] = $val;
                    } else {
                        $args[$key] = array(
                                'data' => $val
                        );
                    }
                }
            }
        } else {
            foreach ($args as $key => $val) {
                if (! is_array($val)) {
                    $args[$key] = array(
                            'data' => $val
                    );
                }
            }
        }
        
        return $args;
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Add a table caption
     *
     * @access public
     * @param
     *            string
     * @return void
     */
    function set_caption ($caption)
    {
        $this->caption = $caption;
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Generate the table
     *
     * @access public
     * @param
     *            mixed
     * @return string
     */
    function generate ($table_data = NULL)
    {
        // The table data can optionally be passed to this function
        // either as a database result object or an array
        if (! is_null($table_data)) {
            if (is_object($table_data)) {
                $this->_set_from_object($table_data);
            } elseif (is_array($table_data)) {
                $set_heading = (count($this->heading) == 0 and
                         $this->auto_heading == FALSE) ? FALSE : TRUE;
                $this->_set_from_array($table_data, $set_heading);
            }
        }
        
        // Is there anything to display? No? Smite them!
        if (count($this->heading) == 0 and count($this->rows) == 0) {
            return 'Undefined table data';
        }
        
        // Compile and validate the template date
        $this->_compile_template();
        
        // set a custom cell manipulation function to a locally scoped variable
        // so its callable
        $function = $this->function;
        
        // Build the table!
        
        $out = $this->template['table_open'];
        $out .= $this->newline;
        
        // Add any caption here
        if ($this->caption) {
            $out .= $this->newline;
            $out .= '<caption>' . $this->caption . '</caption>';
            $out .= $this->newline;
        }
        
        // Is there a table heading to display?
        if (count($this->heading) > 0) {
            $out .= $this->template['thead_open'];
            $out .= $this->newline;
            $out .= $this->template['heading_row_start'];
            $out .= $this->newline;
            
            foreach ($this->heading as $heading) {
                $temp = $this->template['heading_cell_start'];
                
                foreach ($heading as $key => $val) {
                    if ($key != 'data') {
                        $temp = str_replace('<th', "<th $key='$val'", $temp);
                    }
                }
                
                $out .= $temp;
                $out .= isset($heading['data']) ? $heading['data'] : '';
                $out .= $this->template['heading_cell_end'];
            }
            
            $out .= $this->template['heading_row_end'];
            $out .= $this->newline;
            $out .= $this->template['thead_close'];
            $out .= $this->newline;
        }
        
        // Build the table rows
        if (count($this->rows) > 0) {
            $out .= $this->template['tbody_open'];
            $out .= $this->newline;
            
            $i = 1;
            foreach ($this->rows as $row) {
                if (! is_array($row)) {
                    break;
                }
                
                // We use modulus to alternate the row colors
                $name = (fmod($i ++, 2)) ? '' : 'alt_';
                
                $out .= $this->template['row_' . $name . 'start'];
                $out .= $this->newline;
                
                foreach ($row as $cell) {
                    $temp = $this->template['cell_' . $name . 'start'];
                    
                    foreach ($cell as $key => $val) {
                        if ($key != 'data') {
                            $temp = str_replace('<td', "<td $key='$val'", $temp);
                        }
                    }
                    
                    $cell = isset($cell['data']) ? $cell['data'] : '';
                    $out .= $temp;
                    
                    if ($cell === "" or $cell === NULL) {
                        $out .= $this->empty_cells;
                    } else {
                        if ($function !== FALSE && is_callable($function)) {
                            $out .= call_user_func($function, $cell);
                        } else {
                            $out .= $cell;
                        }
                    }
                    
                    $out .= $this->template['cell_' . $name . 'end'];
                }
                
                $out .= $this->template['row_' . $name . 'end'];
                $out .= $this->newline;
            }
            
            $out .= $this->template['tbody_close'];
            $out .= $this->newline;
        }
        
        $out .= $this->template['table_close'];
        
        // Clear table class properties before generating the table
        $this->clear();
        
        return $out;
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Clears the table arrays.
     * Useful if multiple tables are being generated
     *
     * @access public
     * @return void
     */
    function clear ()
    {
        $this->rows = array();
        $this->heading = array();
        $this->auto_heading = TRUE;
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Set table data from a database result object
     *
     * @access public
     * @param
     *            object
     * @return void
     */
    function _set_from_object ($query)
    {
        if (! is_object($query)) {
            return FALSE;
        }
        
        // First generate the headings from the table column names
        if (count($this->heading) == 0) {
            if (! method_exists($query, 'list_fields')) {
                return FALSE;
            }
            
            $this->heading = $this->_prep_args($query->list_fields());
        }
        
        // Next blast through the result array and build out the rows
        
        if ($query->num_rows() > 0) {
            foreach ($query->result_array() as $row) {
                $this->rows[] = $this->_prep_args($row);
            }
        }
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Set table data from an array
     *
     * @access public
     * @param
     *            array
     * @return void
     */
    function _set_from_array ($data, $set_heading = TRUE)
    {
        if (! is_array($data) or count($data) == 0) {
            return FALSE;
        }
        
        $i = 0;
        foreach ($data as $row) {
            // If a heading hasn't already been set we'll use the first row of
            // the array as the heading
            if ($i == 0 and count($data) > 1 and count($this->heading) == 0 and
                     $set_heading == TRUE) {
                $this->heading = $this->_prep_args($row);
            } else {
                $this->rows[] = $this->_prep_args($row);
            }
            
            $i ++;
        }
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Compile Template
     *
     * @access private
     * @return void
     */
    function _compile_template ()
    {
        if ($this->template == NULL) {
            $this->template = $this->_default_template();
            return;
        }
        
        $this->temp = $this->_default_template();
        foreach (array(
                'table_open',
                'thead_open',
                'thead_close',
                'heading_row_start',
                'heading_row_end',
                'heading_cell_start',
                'heading_cell_end',
                'tbody_open',
                'tbody_close',
                'row_start',
                'row_end',
                'cell_start',
                'cell_end',
                'row_alt_start',
                'row_alt_end',
                'cell_alt_start',
                'cell_alt_end',
                'table_close'
        ) as $val) {
            if (! isset($this->template[$val])) {
                $this->template[$val] = $this->temp[$val];
            }
        }
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Default Template
     *
     * @access private
     * @return void
     */
    function _default_template ()
    {
        return array(
                'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
                
                'thead_open' => '<thead>',
                'thead_close' => '</thead>',
                
                'heading_row_start' => '<tr>',
                'heading_row_end' => '</tr>',
                'heading_cell_start' => '<th>',
                'heading_cell_end' => '</th>',
                
                'tbody_open' => '<tbody>',
                'tbody_close' => '</tbody>',
                
                'row_start' => '<tr>',
                'row_end' => '</tr>',
                'cell_start' => '<td>',
                'cell_end' => '</td>',
                
                'row_alt_start' => '<tr>',
                'row_alt_end' => '</tr>',
                'cell_alt_start' => '<td>',
                'cell_alt_end' => '</td>',
                
                'table_close' => '</table>'
        );
    }
}


/* End of file Table.php */
/* Location: ./system/libraries/Table.php */